#include "Level.h"
#include "DrawList.h"
#include "Brick.h"
#include "Model.h"
#include "Renderer.h"

CRenderer* CLevel::m_pRenderer = NULL;

CLevel::CLevel(CPhysics* pPhysics, CDrawList* pDrawList)
	:m_pPhysics(pPhysics), m_pDrawList(pDrawList)
{

	m_fAngle = 0.0f;	//on the begining water is in "0" position

	geomWalls[0] = NULL;
	geomWalls[1] = NULL;
	geomWalls[2] = NULL;
	geomWalls[3] = NULL;

	m_pLeftWallModel = NULL;
	m_pRightWallModel = NULL;
	m_pBackWallModel = NULL;
	m_pFloorModel = NULL;
	m_pWaterModel = NULL;

	//set materials
	m_matWall.d3Diffuse = double3(1.0, 1.0, 1.0);
	m_matWall.d3Specular = double3(0.0, 0.0, 0.0);
	m_matWall.dAlpha = 0.0;
	m_matWall.dShiness = 00.0;

	m_matFloor.d3Diffuse = double3(0.9, 0.9, 0.9);
	m_matFloor.d3Specular = double3(0.1, 0.2, 0.1);
	m_matFloor.dAlpha = 0.0;
	m_matFloor.dShiness = 100.0;

	m_matWater.d3Diffuse = double3(1.0, 1.0, 1.2);
	m_matWater.d3Specular = double3(1.0, 1.0, 1.0);
	m_matWater.dAlpha = 0.0;
	m_matWater.dShiness = 01.0;

	m_dFloorThick = 1.0;
	m_dWallThick = 1.0;
	m_dWallHeight = 2.0;

	m_dFloorTexScale = 1.0;
	m_dWallTexScale = 1.0;
}

CLevel::~CLevel(void)
{
}


void CLevel::SetTransform(double dMatrix[16], double3 d3Pos)
{
	dMatrix[0]=1.0;		//no rotation
	dMatrix[1]=0.0;		//
	dMatrix[2]=0.0;		// - idnentity rotation matrix
	dMatrix[3]=0.0;		//
	dMatrix[4]=0.0;		//
	dMatrix[5]=1.0;		//
	dMatrix[6]=0.0;		//
	dMatrix[7]=0.0;		//
	dMatrix[8]=0.0;		//
	dMatrix[9]=0.0;		//
	dMatrix[10]=1.0;	//
	dMatrix[11]=0;
	dMatrix[12]=d3Pos.x;
	dMatrix[13]=d3Pos.y;
	dMatrix[14]=d3Pos.z;
	dMatrix[15]=1;
}

void CLevel::SetupMatrices(double3 d3Position)
{
	double dMatrix[16];
	SetTransform(dMatrix, d3Position);
	//save this model matrix in renderer
	m_pRenderer->SetModelMatrix(dMatrix);
	
//	glMultMatrixd (dMatrix);

}


int CLevel::Draw()
{

	GLfloat BrownSurface[] = { 0.6f, 0.4f, 0.15f, 1.0f};
	GLfloat WhiteSurface[] = { 1.0f, 1.0f, 1.0f, 1.0f};

	//floor
	m_pRenderer->SetMaterial(m_matFloor);
	SetupMatrices(double3(0.0, -m_dFloorThick/2, 0));
	m_pFloorModel->SetTextureParamui("IN.NormalMap", m_pTexBumpFloor->GetID());
	m_pFloorModel->DrawModel();

	//left wall
	m_pRenderer->SetMaterial(m_matWall);
	SetupMatrices(double3(- (m_fWidth/2 + m_dWallThick/2), m_dWallHeight/2, 0));
//	m_pLeftWallModel->SetTextureParamui("IN.NormalMap", m_pTexBumpWall->GetID());
	m_pLeftWallModel->DrawModel();

	//right wall
	m_pRenderer->SetMaterial(m_matWall);
	SetupMatrices(double3(+ (m_fWidth/2 + m_dWallThick/2), m_dWallHeight/2, 0));
//	m_pRightWallModel->SetTextureParamui("IN.NormalMap", m_pTexBumpWall->GetID());
	m_pRightWallModel->DrawModel();

	//back wall
	if(!g_bTwoPlayers)
	{
		//right wall
		m_pRenderer->SetMaterial(m_matWall);
		SetupMatrices(double3(0, m_dWallHeight/2, -(m_fLength/2 + m_dWallThick/2)));
	//	m_pBackWallModel->SetTextureParamui("IN.NormalMap", m_pTexBumpWall->GetID());
		m_pBackWallModel->DrawModel();
	}

	//water
	m_pRenderer->SetMaterial(m_matWater);
	SetupMatrices(double3(0.0, -(m_dFloorThick*1.5), 0.0));
//	m_pWaterModel->SetTextureParamui("IN.NormalMap", m_pTexBumpWater->GetID());
	m_pWaterModel->SetShaderParamd("IN.Angle", m_fAngle);
	m_pWaterModel->DrawModel();


	return 0;
}

int CLevel::Update()
{
	m_fAngle += 0.004f;
	if(m_fAngle > 2*3.1415) m_fAngle -= 2*3.1415f;
	return 0;
}


/***********************************************************************/
/* Structure of level file:                                            */
/* sx sy [-size of level in box unit]                                  */
/* f [- number of floors]                                              */
/* [for each floor (f times):]                                         */
/* ox oy [floats, offsets in world units (0.0; 1.0) of first box in    */
/*        this floor]                                                  */
/* [sx*sy integers (0; 255) that describes board. 0 means empty, 1 is  */
/*  normal box. Given in column-major order]                           */
/***********************************************************************/

int CLevel::LoadLevel(const char* szFileName)
{
	FILE* fileLevel;
	int iSX, iSY, iF;
	float fOX, fOY;

	//remove walls and floor, if it exists
	if(geomWalls[0]) dGeomDestroy(geomWalls[0]);
	if(geomWalls[1]) dGeomDestroy(geomWalls[1]);
	if(geomWalls[2]) dGeomDestroy(geomWalls[2]);
	if(geomWalls[3]) dGeomDestroy(geomWalls[3]);

	DELETE_OBJECT(m_pLeftWallModel);
	DELETE_OBJECT(m_pRightWallModel);
	DELETE_OBJECT(m_pBackWallModel);
	DELETE_OBJECT(m_pFloorModel);
	DELETE_OBJECT(m_pWaterModel);

	fopen_s(&fileLevel, szFileName, "r");		//open file

	fscanf_s(fileLevel, "%d %d %d", &iSX, &iSY, &iF, 100);	//read size and number of floors

	m_fWidth = iSX*1.1f;		//leave space for gaps between boxes
	m_fLength = iSY*1.1f;

	//create new floor and walls
	//floor
	geomWalls[0] = dCreatePlane(m_pPhysics->GetSpace(), 0, 1, 0, 0);
	//left wall
	geomWalls[1] = dCreatePlane(m_pPhysics->GetSpace(), 1, 0, 0, -m_fWidth/2);
	//right wall
	geomWalls[2] = dCreatePlane(m_pPhysics->GetSpace(), -1, 0, 0, -m_fWidth/2);

	if(!g_bTwoPlayers)
	{
		//top
		geomWalls[3] = dCreatePlane(m_pPhysics->GetSpace(), 0, 0, 1, -m_fLength/2);
	}

		//load models
	m_pLeftWallModel = new CModel(true);
	m_pLeftWallModel->CreateTexBox((float)m_dWallThick, (float)m_dWallHeight, m_fLength, 0.5f, 0.5f, m_fLength/10);
	m_pLeftWallModel->LoadShader("data//shaders//simplepix.cg");
	m_pLeftWallModel->LoadTexture("data//images//wall.png");

	m_pRightWallModel = new CModel(true);
	m_pRightWallModel->CreateTexBox((float)m_dWallThick, (float)m_dWallHeight, m_fLength, 0.5f, 0.5f, m_fLength/10);
	m_pRightWallModel->LoadShader("data//shaders//simplepix.cg");
	m_pRightWallModel->LoadTexture("data//images//wall.png");

	m_pBackWallModel = new CModel(true);
	m_pBackWallModel->CreateTexBox(m_fWidth + (float)m_dWallThick*2, (float)m_dWallHeight, (float)m_dWallThick, m_fWidth/7, 0.5f, 0.5f);
	m_pBackWallModel->LoadShader("data//shaders//simplepix.cg");
	m_pBackWallModel->LoadTexture("data//images//wall.png");

	m_pFloorModel = new CModel(true);	//model with multiple textures
	m_pFloorModel->CreateTexBox(m_fWidth + (float)m_dWallThick*2, (float)m_dFloorThick, m_fLength, 2.0f, 0.1f, 2.0f);
	m_pFloorModel->LoadShader("data//shaders//bumpup.cg");
	m_pFloorModel->LoadTexture("data//images//floor.png");

	m_pWaterModel = new CModel(true);
	m_pWaterModel->CreateTexBox(m_fWidth*5, (float)m_dFloorThick, m_fLength*3, 10.0f, 0.1f, 10.0f);
	m_pWaterModel->LoadShader("data//shaders//water.cg");
	m_pWaterModel->LoadTexture("data//images//water.png");




	LoadTextures();

	//read iF floors
	for(int i=0; i<iF; i++)
	{
		fscanf_s(fileLevel, "%f %f", &fOX, &fOY);	//read offsets
		for(int y=0; y<iSY; y++){
			for(int x=0; x<iSX; x++){
				int iType;
				fscanf_s(fileLevel, "%d", &iType);	//read brick type

				if(iType != 0)	//if not empty:
				{
					//create new brick in proper position
					CBrick* pBrick = new CBrick();
					pBrick->SetPosition(0.5 + fOX + x - iSX/2., 0.9 + i, 0.5 + fOY + y - iSY/2.);
					m_pDrawList->AddObject(pBrick);
				}

			}
		}
	}

	fclose(fileLevel);
	
	//return created level object
	return 0;	//OK
}

void CLevel::LoadTextures()
{
	m_pTexBumpFloor = CTextureManager::GetInstance()->GetTexture("data//images//floorBump.png");
	m_pTexBumpFloor->Bind();	//without mipmaps
	m_pTexBumpWall = CTextureManager::GetInstance()->GetTexture("data//images//wallBump.png");
	m_pTexBumpWall->Bind();	//without mipmaps
	m_pTexBumpWater = CTextureManager::GetInstance()->GetTexture("data//images//waterBump.png");
	m_pTexBumpWater->Bind();	//without mipmaps
}

void CLevel::SetRenderer(CRenderer* pRenderer)
{
	m_pRenderer = pRenderer;
}